/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#ifndef MK_SOCKET_H
#define MK_SOCKET_H
#include "MkUtil/MkBuffer.h"
#include "MkUtil/MkLock.h"
#include "MkUtil/MkTime.h"
#include <atomic>

#define DefauleBackLog  5
#define DefaultCloseWait	0

class CMkEvent;
class CMkTimer;
class MkApi CMkSocket
{
public:
    typedef enum _mk_socket_type
    {
        TcpListener = 1,
        TcpClient = 2,
        TcpSession = 3,
        UdpSession = 4
    }MkSocketType;
public:
    CMkSocket(const MkSocketType& SocketType, CMkEvent* pEvent, CMkTimer* pTimer);
    virtual ~CMkSocket();
    const MkSocketType &SocketType() const { return m_SockType; }
    const Uint16& GetLocalPort() const { return m_LocalPort; }
    const Uint16& GetRemotePort() const { return m_RemotePort; }
    const MkString& GetLocalHost() const { return m_LocalHost; }
    const MkString& GetRemoteHost() const { return m_RemoteHost; }
    const Uint64& GetSessionId() const { return m_SessionId; }
    const BOOL& IsConnected() const { return m_bConntected; }
    const CMkTime& GetActiveTime() const { return m_ActiveTime; }
    Uint32 GetUnSendBufferLength() const;
    const SOCKET& Socket() const { return m_Socket; }
    void SetEvent(CMkEvent* pEvent) { m_pEvent = pEvent; }
    CMkEvent* GetEvent() const { return m_pEvent; }
    CMkTimer* GetTimer() const { return m_pTimer; }
    Uint32 SetSocket(SOCKET sock, Uint32 Event);
    Uint32 Create(BOOL bReuse = TRUE);
    Uint32 Bind(Uint16 Port, const MkString& Ip = "");
    Uint32 Listen(int BackLog = DefauleBackLog);
    Uint32 SetNoDelay(BOOL bOn = TRUE);
    Uint32 SetNoSigpipe(BOOL bOn = TRUE);
    Uint32 SetNoBlocked(BOOL bOn = TRUE);
    Uint32 SetRecvBufferLen(int nSize = Len1M);
    Uint32 SetSendBufferLen(int nSize = Len1M);
    Uint32 SetReuseable(BOOL bOn = TRUE);
    Uint32 SetKeepAlive(BOOL bOn = TRUE);
    Uint32 SetCloseWait(Uint32 Second = DefaultCloseWait);
    Uint32 SetCloExec(BOOL bOn = TRUE);
    Uint32 SetConnectTimeOut(Uint32 nSeconds);
    Uint32 Accept(CMkSocket* pAccectSock);

    Uint32 Connect(const MkString& Ip, Uint16 Port);
    virtual Uint32 Send(const Uint8* pBuf, Uint32 nLen);
    virtual Uint32 Send(const CMkBufferList& BufList);
    virtual Uint32 Recv(Uint8* pBuf, INOUT Uint32& nLen);
    virtual Uint32 SendTo(const MkString& Ip, Uint16 Port, const Uint8* pBuf, Uint32 nLen);
    virtual Uint32 SendTo(const MkString& Ip, Uint16 Port, const CMkBufferList& BufferList);
    virtual Uint32 SendTo(const struct sockaddr_in& Dest, const Uint8* pBuf, Uint32 nLen);
    virtual Uint32 SendTo(const struct sockaddr_in& Dest, const CMkBufferList& BufferList);
    virtual Uint32 RecvFrom(Uint8* pBuf, INOUT Uint32& nLen, OUT MkString& Ip, OUT Uint16& Port);
    virtual Uint32 Close();

    virtual Uint32 OnRecv();
    virtual Uint32 OnRecvFrom();
    virtual Uint32 OnAccept();
    virtual Uint32 OnConnect();
    virtual Uint32 OnClose();
    virtual Uint32 OnWrite();
    virtual Uint32 OnEventRemoved();

    static Uint64 GetTcpActiveMs() { return m_TcpActiveMs; }
    static Uint32 GetTcpSendFailCumulativeMs() { return m_TcpSendFailCumulativeMs; }
    static Uint32 GetTcpSendFailCumulativeMB() { return m_TcpSendFailCumulativeMB; }
    static Uint32 GetUdpSendFailCumulativeMs() { return m_UdpSendFailCumulativeMs; }
    static Uint32 GetUdpSendFailCumulativeMB() { return m_UdpSendFailCumulativeMB; }

    static void SetTcpActiveMs(Uint32 Ms) { m_TcpActiveMs = Ms; }
    static void SetTcpSendFailCumulativeMs(Uint32 Ms) { m_TcpSendFailCumulativeMs = Ms; }
    static void SetTcpSendFailCumulativeMB(Uint32 MB) { m_TcpSendFailCumulativeMB = MB; }
    static void SetUdpSendFailCumulativeMs(Uint32 Ms) { m_UdpSendFailCumulativeMs = Ms; }
    static void SetUdpSendFailCumulativeMB(Uint32 MB) { m_UdpSendFailCumulativeMB = MB; }
private:
    void OnEvent(Uint32 Event);
    void OnEventRead();
    Uint32 GetPeerAddr();
    Uint32 GetLocalAddr();
private:
    MkSocketType    m_SockType;
    SOCKET          m_Socket;
    Uint16          m_RemotePort;
    MkString        m_RemoteHost;    //tcp used
    Uint16          m_LocalPort;
    MkString        m_LocalHost;
    CMkEvent*       m_pEvent;
    CMkTimer*       m_pTimer;

    std::atomic<BOOL>               m_bWriteAble;
    CMkLock                         m_UnSendLock;
    CMkStorageBufferList            m_UnSendList;
    MkVector<CMkStorageBufferList>  m_UdpUnSendList;
    BOOL                            m_bConntected;
    Uint64                          m_TotalSendLen;
    Uint64                          m_TotalRecvLen;
    Uint64                          m_SessionId;
    CMkTime                         m_ActiveTime;

    static Uint64                   m_SessionIndex;
    static Uint64                   m_TcpActiveMs;                  //tcp active milliseconds for close
    static Uint32                   m_TcpSendFailCumulativeMs;      //Cumulative milliseconds of tcp sending failure will close
    static Uint32                   m_TcpSendFailCumulativeMB;      //Cumulative MB of tcp sending failure will close
    static Uint32                   m_UdpSendFailCumulativeMB;      //Cumulative MB of udp sending failure will clear
    static Uint32                   m_UdpSendFailCumulativeMs;      //Cumulative milliseconds of udp sending failure will clear 
};

#endif //MK_SOCKET_H
